package com.bfly.mall.wechat.mp.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bfly.common.json.JsonUtil;
import com.bfly.common.util.NetUtil;
import com.bfly.core.base.entity.RemoteResponse;
import com.bfly.core.enums.SysError;
import com.bfly.core.exception.ServiceResponseException;
import com.bfly.mall.wechat.common.WeChatAPi;
import com.bfly.mall.wechat.common.WeChatAssert;
import com.bfly.mall.wechat.common.WeChatHttpUtil;
import com.bfly.mall.wechat.mp.dto.*;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.List;

/**
 * 微信公众号API接口
 *
 * @author 长沙商脉科技有限公司
 * @date 2020/5/9 11:40
 */
public class WeChatMPAPi {

    private static Logger logger = LoggerFactory.getLogger(WeChatMPAPi.class);

    /**
     * 为了满足用户渠道推广分析和用户帐号绑定等场景的需要，公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/4 21:35
     */
    public static final String QR_CODE = "https://api.weixin.qq.com/cgi-bin/qrcode/create";

    /**
     * 公众号可通过本接口来获取帐号的关注者列表，关注者列表由一串OpenID（加密后的微信号，每个用户对每个公众号的OpenID是唯一的）组成。
     * 一次拉取调用最多拉取10000个关注者的OpenID，可以通过多次拉取的方式来满足需求。
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/5 19:43
     */
    public static final String SYNC_USER = "https://api.weixin.qq.com/cgi-bin/user/get";

    /**
     * 在关注者与公众号产生消息交互后，公众号可获得关注者的OpenID（加密后的微信号，每个用户对每个公众号的OpenID是唯一的。对于不同公众号，同一用户的openid不同）。公众号可通过本接口来根据OpenID获取用户基本信息，包括昵称、头像、性别、所在城市、语言和关注时间。
     * <p>
     * 请注意，如果开发者有在多个公众号，或在公众号、移动应用之间统一用户帐号的需求，需要前往微信开放平台（open.weixin.qq.com）绑定公众号后，才可利用UnionID机制来满足上述需求。
     * 开发者可通过该接口来批量获取用户基本信息。最多支持一次拉取100条。
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/5 20:16
     */
    public static final String USER_INFO = "https://api.weixin.qq.com/cgi-bin/user/info/batchget";

    /**
     * 自定义菜单最多包括3个一级菜单，每个一级菜单最多包含5个二级菜单。
     * 一级菜单最多4个汉字，二级菜单最多7个汉字，多出来的部分将会以“...”代替。
     * 创建自定义菜单后，菜单的刷新策略是，在用户进入公众号会话页或公众号profile页时，如果发现上一次拉取菜单的请求在5分钟以前，就会拉取一下菜单，如果菜单有更新，就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注，则可以看到创建后的效果。​
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/7 16:30
     */
    public static final String CREATE_MENU = "https://api.weixin.qq.com/cgi-bin/menu/create";

    /**
     * 使用接口创建自定义菜单后，开发者还可使用接口删除当前使用的自定义菜单。另请注意，在个性化菜单时，调用此接口会删除默认菜单及全部个性化菜单。
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 10:20
     */
    public static final String CLEAR_MENU = "https://api.weixin.qq.com/cgi-bin/menu/delete";

    /**
     * 1、获取永久素材的列表，也包含公众号在公众平台官网素材管理模块中新建的图文消息、语音、视频等素材
     * 2、临时素材无法通过本接口获取
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 10:30
     */
    public static final String FOREVER_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material";

    /**
     * 在新增了永久素材后，开发者可以根据media_id通过本接口下载永久素材。公众号在公众平台官网素材管理模块中新建的永久素材，可通过"获取素材列表"获知素材的media_id。
     * <p>
     * 请注意：临时素材无法通过本接口获取
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 16:20
     */
    public static final String MATERIAL_INFO = "https://api.weixin.qq.com/cgi-bin/material/get_material";

    /**
     * 通过POST表单来调用接口，表单id为media，包含需要上传的素材内容，有filename、filelength、content-type等信息。请注意：图片素材将进入公众平台官网素材管理模块中的默认分组。
     * 媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb） ，图文素材不适用该接口
     * http请求方式: POST，需使用https https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/9 18:44
     */
    public static final String ADD_NORMAL_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/add_material";

    /**
     * 上传图文素材
     * @author 长沙商脉科技有限公司
     * @date 2021/1/11 19:37
     */
    public static final String ADD_NEWS_MATERIAL="https://api.weixin.qq.com/cgi-bin/material/add_news";

    /**
     * 编辑图文素材
     * @author 长沙商脉科技有限公司
     * @date 2021/1/12 12:39
     */
    public static final String EDIT_NEWS_MATERIAL="https://api.weixin.qq.com/cgi-bin/material/update_news";


    /**
     * 1、请谨慎操作本接口，因为它可以删除公众号在公众平台官网素材管理模块中新建的图文消息、语音、视频等素材（但需要先通过获取素材列表来获知素材的media_id）
     * 2、临时素材无法通过本接口删除 3、调用该接口需https协议
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/10 11:40
     */
    public static final String DELETE_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/del_material";


    /**
     * 本接口所上传的图片不占用公众号的素材库中图片数量的100000个的限制。图片仅支持jpg/png格式，大小必须在1MB以下。
     * @author 长沙商脉科技有限公司
     * @date 2021/1/19 21:47
     */
    public static final String UPLOAD_NEWS_IMG_MATERIAL="https://api.weixin.qq.com/cgi-bin/media/uploadimg";

    /**
     * 获取小程序全局唯一后台接口调用凭据
     *
     * @author 长沙商脉科技有限公司
     * @date 2020/11/12 15:07
     */
    private static String getAccessToken(String appId, String appSecret) {
        String accessToken = WeChatAPi.getAccessToken(appId, appSecret);
        return accessToken;
    }

    /**
     * 获取微信公众号二维码，永久有效，有数量限制一般用于推广场景
     *
     * @author andy_hulibo@163.com
     * @date 2020/12/20 13:30
     */
    public static String getMpQrCode(String appId, String appSecret) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.QR_CODE.concat("?access_token=" + getAccessToken(appId, appSecret));
            HttpPost post = new HttpPost(url);

            JSONObject json = new JSONObject();
            json.put("action_name", "QR_LIMIT_SCENE");

            JSONObject sceneJson = new JSONObject();
            sceneJson.put("scene_id", 1);

            JSONObject actionJson = new JSONObject();
            actionJson.put("scene", sceneJson);

            json.put("action_info", actionJson);

            StringEntity entity = new StringEntity(json.toJSONString());
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
        JSONObject json = JsonUtil.parse(response.getBody(), JSONObject.class);
        return json.getString("url");
    }

    /**
     * 同步公众号用户
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/5 19:42
     */
    public static WeChatMpUserSynResponse syncMpUser(String appId, String appSecret, String nextOpenId) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.SYNC_USER.concat("?access_token=" + getAccessToken(appId, appSecret)).concat("&next_openid=" + nextOpenId);
            HttpGet get = new HttpGet(url);
            response = WeChatHttpUtil.weChatHttpRequest(get);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
        WeChatMpUserSynResponse result = JsonUtil.parse(response.getBody(), WeChatMpUserSynResponse.class);
        return result;
    }

    /**
     * 获取用户基本信息
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/5 20:16
     */
    public static List<WeChatMpUserInfo> getMpUserInfo(String appId, String appSecret, List<WeChatMpUserInfoRequest> list) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.USER_INFO.concat("?access_token=" + getAccessToken(appId, appSecret));
            JSONObject json = new JSONObject();
            json.put("user_list", list);

            HttpPost post = new HttpPost(url);
            StringEntity entity = new StringEntity(json.toJSONString());
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
        JSONObject result = JsonUtil.parse(response.getBody(), JSONObject.class);
        JSONArray array = result.getJSONArray("user_info_list");
        List<WeChatMpUserInfo> userInfos = JsonUtil.parseStrToList(array.toJSONString(), WeChatMpUserInfo.class);
        return userInfos;
    }

    /**
     * 创建自定义菜单
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/7 16:33
     */
    public static void createMenu(String appId, String appSecret, JSONObject json) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.CREATE_MENU.concat("?access_token=" + getAccessToken(appId, appSecret));

            HttpPost post = new HttpPost(url);
            StringEntity entity = new StringEntity(json.toJSONString(), "UTF-8");
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
    }

    /**
     * 删除自定义菜单
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 10:19
     */
    public static void clearMenu(String appId, String appSecret) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.CLEAR_MENU.concat("?access_token=" + getAccessToken(appId, appSecret));
            HttpGet get = new HttpGet(url);
            response = WeChatHttpUtil.weChatHttpRequest(get);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
    }

    /**
     * 获取永久素材的列表
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 10:31
     */
    public static WeChatMpForeverMaterialListResponse getForeverMaterialList(String appId, String appSecret, WeChatMpForeverMaterialListRequest request) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.FOREVER_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret));

            HttpPost post = new HttpPost(url);
            JSONObject json = JsonUtil.toJsonFilter(request);
            StringEntity entity = new StringEntity(json.toJSONString(), "UTF-8");
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);

        WeChatMpForeverMaterialListResponse materialResponse = JsonUtil.parse(response.getBody(), WeChatMpForeverMaterialListResponse.class);
        return materialResponse;
    }

    /**
     * 获得永久素材详细信息--图文和视频消息素材
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 16:21
     */
    public static WeChatMpForeverMaterialInfoResponse getForeverMaterial(String appId, String appSecret, String mediaId) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.MATERIAL_INFO.concat("?access_token=" + getAccessToken(appId, appSecret));

            HttpPost post = new HttpPost(url);
            JSONObject json = new JSONObject();
            json.put("media_id", mediaId);
            StringEntity entity = new StringEntity(json.toJSONString(), "UTF-8");
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);

        WeChatMpForeverMaterialInfoResponse materialResponse = JsonUtil.parse(response.getBody(), WeChatMpForeverMaterialInfoResponse.class);
        return materialResponse;
    }

    /**
     * 获得多媒体流--图片，语音
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/8 16:21
     */
    public static byte[] getImageOrVoiceMaterial(String appId, String appSecret, String mediaId) {
        try {
            String url = WeChatMPAPi.MATERIAL_INFO.concat("?access_token=" + getAccessToken(appId, appSecret));

            HttpPost post = new HttpPost(url);
            JSONObject json = new JSONObject();
            json.put("media_id", mediaId);
            StringEntity entity = new StringEntity(json.toJSONString(), "UTF-8");
            post.setEntity(entity);
            try (CloseableHttpResponse client = NetUtil.getHttpClient().execute(post)) {
                HttpEntity httpEntity = client.getEntity();
                byte[] bytes = IOUtils.toByteArray(httpEntity.getContent());
                return bytes;
            } catch (Exception e) {
                throw new ServiceResponseException(SysError.REMOTE_ERROR, "远程服务异常:" + e.getMessage());
            } finally {
                post.releaseConnection();
            }
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
    }

    /**
     * 新增永久素材---图文素材不适用该接口
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/9 18:48
     */
    public static WeChatMpAddForeverMaterialResponse addForeverMaterial(String appId, String appSecret, WeChatMpAddForeverMaterialRequest request) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.ADD_NORMAL_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret)).concat("&type=" + request.getType());

            File file = new File(request.getFile());
            FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY,request.getFileName());
            MultipartEntityBuilder builder=MultipartEntityBuilder.create().addPart("media", fileBody);
            if(request.getType().equalsIgnoreCase("video")){
                JSONObject json=new JSONObject();
                json.put("title",request.getTitle());
                json.put("introduction",request.getRemark());
                builder.addTextBody("description",json.toJSONString(),ContentType.APPLICATION_JSON);
            }
            HttpEntity entity = builder.setMode(HttpMultipartMode.RFC6532).build();
            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);

        WeChatMpAddForeverMaterialResponse materialResponse = JsonUtil.parse(response.getBody(), WeChatMpAddForeverMaterialResponse.class);
        return materialResponse;
    }

    /**
     * 新增图文永久素材
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/9 18:48
     */
    public static WeChatMpAddForeverMaterialResponse addForeverMaterial(String appId, String appSecret, WeChatMpAddForeverNewsMaterialRequest request) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.ADD_NEWS_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret));

            String json=JsonUtil.toJsonFilter(request).toJSONString();
            StringEntity entity=new StringEntity(json,"UTF-8");
            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);

        WeChatMpAddForeverMaterialResponse materialResponse = JsonUtil.parse(response.getBody(), WeChatMpAddForeverMaterialResponse.class);
        return materialResponse;
    }

    /**
     * 编辑图文永久素材
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/9 18:48
     */
    public static void editForeverMaterial(String appId, String appSecret, WeChatMpEditForeverNewsMaterialRequest request) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.EDIT_NEWS_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret));

            String json=JsonUtil.toJsonFilter(request).toJSONString();
            StringEntity entity=new StringEntity(json,"UTF-8");
            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
    }

    /**
     * 删除永久素材
     *
     * @author 长沙商脉科技有限公司
     * @date 2021/1/10 11:39
     */
    public static void deleteForeverMaterial(String appId, String appSecret, String mediaId) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.DELETE_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret));

            JSONObject json = new JSONObject();
            json.put("media_id", mediaId);
            StringEntity entity=new StringEntity(json.toJSONString());

            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);
    }

    /**
     * 上传图文素材内容中的图片
     * @author 长沙商脉科技有限公司
     * @date 2021/1/19 21:49
     */
    public static WeChatMpAddForeverMaterialResponse addNewsContentImgMaterial(String appId, String appSecret, WeChatMpAddForeverMaterialRequest request) {
        RemoteResponse response;
        try {
            String url = WeChatMPAPi.UPLOAD_NEWS_IMG_MATERIAL.concat("?access_token=" + getAccessToken(appId, appSecret));

            File file = new File(request.getFile());
            FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY,request.getFileName());
            MultipartEntityBuilder builder=MultipartEntityBuilder.create().addPart("media", fileBody);
            HttpEntity entity = builder.setMode(HttpMultipartMode.RFC6532).build();
            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            response = WeChatHttpUtil.weChatHttpRequest(post);
        } catch (Exception e) {
            throw new ServiceResponseException(SysError.REMOTE_ERROR, e.getMessage());
        }
        WeChatAssert.checkResponse(response);

        WeChatMpAddForeverMaterialResponse materialResponse = JsonUtil.parse(response.getBody(), WeChatMpAddForeverMaterialResponse.class);
        return materialResponse;
    }
}